use std::{fs, io, path::Path};

use colored::Colorize;
use rig::{completion::ToolDefinition, tool::Tool};
use serde::{Deserialize, Serialize};
use serde_json::json;

#[derive(Deserialize)]
pub struct OperationArgs {
    path: String,
}

#[derive(Debug, thiserror::Error)]
#[error("Math error")]
pub struct LsError;

#[derive(Deserialize, Serialize)]
pub struct LsCmd {
    pub project_path: String,
}

impl Tool for LsCmd {
    const NAME: &'static str = "ls";

    type Error = LsError;
    type Args = OperationArgs;
    type Output = String;

    async fn definition(&self, _prompt: String) -> ToolDefinition {
        ToolDefinition {
            name: "ls".to_string(),
            description: "提供文件路径，输出路径下的文件列表,当前项目路径使用\".\"".to_string(),
            parameters: json!({
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "the path needed to known"
                    }
                }
            }),
        }
    }

    async fn call(&self, args: Self::Args) -> Result<Self::Output, Self::Error> {
        println!("{}", format!("ls {}", args.path).red());
        let res = ls(&self.project_path, args.path);
        Ok(res)
    }
}

fn ls(pwd: &String, path: String) -> String {
    let base_path = Path::new(pwd);
    let real_path_op = base_path
        .join(&path)
        .canonicalize()
        .map(|it| it.display().to_string());

    if let Ok(real_path) = real_path_op {
        let mut files = Vec::<String>::new();

        if let Ok(entries) = fs::read_dir(&real_path) {
            for entry in entries {
                if let Ok(entry) = entry {
                    let path = entry.file_name();
                    files.push(format!("{}", path.to_str().unwrap_or("")));
                }
            }
        }

        return format!("路径 {} 的文件列表\n{}", path, files.join("\n"));
    } else {
        return format!("路径 {} 不存在", path);
    }
}
